#ifndef __LSV_H__
#define __LSV_H__

#include "schedule.h"
#include "coroutine.h"

#include "dbg.h"
#include "list.h"
#include "lsv_conf.h"
#include "lsv_types.h"
#include "lsv_lib.h"
#include "lock_table.h"
// #include "lsv_thread_queue.h"

#ifndef VERSION
#define VERSION "1.0.0"
#endif

#define LSV_LOW_VOL_TEST         0
#define LSV_LOW_VOL_TEST2        0

#if 1
#define LSV_DBUG(...)
#else
#define LSV_DBUG DINFO
#endif

struct __volume_proto;

typedef struct __lsv_info_t {
        struct __volume_proto *volume_proto;

//        struct list_head vp_list; ////filled in volume create
        lsv_s32_t sock_fd;//socket id , connect remote mirror site
        lsv_s32_t rc_id;//remote mirror, identify which is master or slave

        uint64_t max_size;
        uint64_t size;

        lsv_ino_t ino;
        volume_format_t volume_format;

        void *log_info; //filled in log init

        void *volgc_info; ////filled in volume create

        void *storage_info; //filled in storage create,must init NULL

        void *bitmap_context;

        void *wbuf;  /*lsv_wbuffer.h lsv_wbuf_vol_mem_t, manage wbuf memory*/

        void *rcache;/*lsv_rcache.h lsv_rcache_vol_mem_t contain chunk_buf*/

        // for 2M range
        lock_table_t lock_table;

        // for meta COW
        lock_table_t bitmap_cow_lt;

        // for LSV
        hashtable_t io_hash;
        hashtable_t lba_fifo;

        // 写入数据用读锁，可以并发
        // flush用写锁
        lsv_rwlock_t io_lock;
        lsv_rwlock_t info_lock;
        lsv_rwlock_t loading_lock;      //loading..

        struct {
                lsv_rwlock_t tail_lock;
                uint32_t chunk_id;
                uint32_t chunk_off;
        } row3_tail;

        struct {
                void *extent_ring;
                void *bitmap_ring;
                void *async_ring;
        } row3_rings;

        void *test_volume_context;
        // 尚未提交的IO
        count_list_t io_stream;

        void *chunk_pool;

        /*
         * Structure stored on volume chunk 0
         * 接着是用于空间管理的volume bitmap, 32*2 = 64个chunk
         * chunk 65: log的？
         * chunk 66: 第一个bitmap heaader？
         */
        struct {
                // page 1
                uint32_t volume_page_id;

                // page 2
                uint32_t gc_os_page_id;

                // page 3
                uint32_t gc_bitmap_page_id;

                // 记录ssd cache的chunk_id，共4页，[4,7]，最多表示4096个chunk
                uint32_t rcache_page_id;

                // 记录wal2的检查点和所用chunk_id: page 8
                uint32_t wbuf_page_id;

                // bitmap header的第一个chunk_id，一个bitmap header占据连续多个chunk
                // 多个bitmap header构成快照树
                uint32_t bitmap_chunk_id;

                // 系统是否异常关闭：0：create，1：load, 2：recover
                uint32_t system_power_on;

                uint32_t start_mode;
                uint32_t safe_mode;
        } u;

        // stat
        uint64_t write_count;
        uint64_t wbuf_write_count;
        uint64_t wbuf_write_end_count;

        uint64_t log_write_count;
        uint64_t log_commit_count;

        uint64_t bitmap_write_count;
        uint64_t bitmap_batch_write_count;

        uint64_t input_bytes;
        uint64_t log_bytes;
        uint64_t commit_bytes;

        // read stat
        uint64_t read_wbuf_hit;
        uint64_t read_wbuf_miss;
        uint64_t read_page_miss;

        uint64_t read_rc_hit;
        uint64_t read_rc_miss;

        time_count_t tc;

        struct {
                uint32_t wbuf_chunk_idx;

                uint64_t gc_merge_enter_count;
                uint64_t write_enter_count;
                uint64_t malloc_chunk_enter_count;
                uint64_t write_log_enter_count;
                uint64_t update_bitmap_enter_count;
        } share;

        struct {
                uint64_t malloc;
                uint64_t write;
                uint64_t read;

                uint64_t head_malloc;
                uint64_t head_write;
                uint64_t head_read;

                uint64_t meta_malloc;
                uint64_t meta_write;
                uint64_t meta_read;

                uint64_t data_malloc;
                uint64_t data_write;
                uint64_t data_read;
                uint64_t data_remote_read;

                uint64_t cache_swapin;
                uint64_t cache_swapout;
                uint64_t cache_page_write;
                uint64_t cache_page_read;

                uint64_t align_write;
                uint64_t align_read;
        } row2_stat;

        op_stat_t op_stat[OP_MAX];

        void *crc_context;
} lsv_volume_proto_t;

int lsv_conf_init();

int lsv_info_check_ready(lsv_volume_proto_t *lsv_info);

void lsv_info_print_io_stream(lsv_volume_proto_t *lsv_info);

int lsv_info_set_poweroff(lsv_volume_proto_t *lsv_info, uint32_t power_off);

// for LSV
int lsv_info_format(lsv_volume_proto_t *lsv_info);

int lsv_info_init(lsv_volume_proto_t *lsv_info);

int lsv_info_destroy(lsv_volume_proto_t *lsv_info);

void lsv_info_stat(lsv_volume_proto_t *lsv_info);

int lsv_info_setattr(lsv_volume_proto_t *lsv_info);

// utils
static inline lsv_u64_t __chkid2voloffset(uint32_t chunk_id) {
        return ((lsv_u64_t) LSV_CHUNK_SIZE) * chunk_id;
}

// page model
int lsv_page_read_nolock(lsv_volume_proto_t *volume_proto, uint64_t offset, uint32_t size,
                  raw_io_t * rio, buffer_t *append_buf);

int lsv_page_write_with_align(void *arg);

// object model: IO, chunk etc

// for ROW2
int row2_info_format(lsv_volume_proto_t *lsv_info);

int row2_info_init(lsv_volume_proto_t *lsv_info);

int row2_info_destroy(lsv_volume_proto_t *lsv_info, int is_flush);

int row3_info_format(lsv_volume_proto_t *lsv_info);

int row3_info_init(lsv_volume_proto_t *lsv_info);

int row3_info_destroy(lsv_volume_proto_t *lsv_info, int is_flush);

#endif
